<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
        "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <link href="../Styles/sure3.css" rel="stylesheet" type="text/css"/>
    <link href="../Styles/base1.css" rel="stylesheet" type="text/css"/>
</head>

<body>
<div class="markdown-body entry-content" itemprop="text">
    <h1><a href="#正则的扩展"  class="anchor" id="user-content-正则的扩展">

    </a>正则的扩展
    </h1>
    <h2><a href="#regexp-构造函数"  class="anchor" id="user-content-regexp-构造函数">

    </a>RegExp 构造函数
    </h2>
    <p>在 ES5 中，<code>RegExp</code>构造函数的参数有两种情况。</p>
    <p>第一种情况是，参数是字符串，这时第二个参数表示正则表达式的修饰符（flag）。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> regex <span
            class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">RegExp</span>(<span
            class="pl-s"><span class="pl-pds">'</span>xyz<span class="pl-pds">'</span></span>, <span class="pl-s"><span
            class="pl-pds">'</span>i<span class="pl-pds">'</span></span>);
<span class="pl-c"><span class="pl-c">//</span> 等价于</span>
<span class="pl-k">var</span> regex <span class="pl-k">=</span><span class="pl-sr"> <span
                class="pl-pds">/</span>xyz<span class="pl-pds">/</span>i</span>;</pre>
    </div>
    <p>第二种情况是，参数是一个正则表示式，这时会返回一个原有正则表达式的拷贝。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> regex <span
            class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">RegExp</span>(<span
            class="pl-sr"><span class="pl-pds">/</span>xyz<span class="pl-pds">/</span>i</span>);
<span class="pl-c"><span class="pl-c">//</span> 等价于</span>
<span class="pl-k">var</span> regex <span class="pl-k">=</span><span class="pl-sr"> <span
                class="pl-pds">/</span>xyz<span class="pl-pds">/</span>i</span>;</pre>
    </div>
    <p>但是，ES5 不允许此时使用第二个参数添加修饰符，否则会报错。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> regex <span
            class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">RegExp</span>(<span
            class="pl-sr"><span class="pl-pds">/</span>xyz<span class="pl-pds">/</span></span>, <span class="pl-s"><span
            class="pl-pds">'</span>i<span class="pl-pds">'</span></span>);
<span class="pl-c"><span class="pl-c">//</span> Uncaught TypeError: Cannot supply flags when constructing one RegExp from another</span></pre>
    </div>
    <p>ES6 改变了这种行为。如果<code>RegExp</code>构造函数第一个参数是一个正则对象，那么可以使用第二个参数指定修饰符。而且，返回的正则表达式会忽略原有的正则表达式的修饰符，只使用新指定的修饰符。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">new</span> <span
            class="pl-en">RegExp</span>(<span class="pl-sr"><span class="pl-pds">/</span>abc<span
            class="pl-pds">/</span>ig</span>, <span class="pl-s"><span class="pl-pds">'</span>i<span
            class="pl-pds">'</span></span>).<span class="pl-smi">flags</span>
<span class="pl-c"><span class="pl-c">//</span> "i"</span></pre>
    </div>
    <p>上面代码中，原有正则对象的修饰符是<code>ig</code>，它会被第二个参数<code>i</code>覆盖。</p>
    <h2><a href="#字符串的正则方法"  class="anchor" id="user-content-字符串的正则方法">

    </a>字符串的正则方法
    </h2>
    <p>字符串对象共有 4 个方法，可以使用正则表达式：<code>match()</code>、<code>replace()</code>、<code>search()</code>和<code>split()</code>。
    </p>
    <p>ES6 将这 4 个方法，在语言内部全部调用<code>RegExp</code>的实例方法，从而做到所有与正则相关的方法，全都定义在<code>RegExp</code>对象上。</p>
    <ul>
        <li><code>String.prototype.match</code> 调用 <code>RegExp.prototype[Symbol.match]</code></li>
        <li><code>String.prototype.replace</code> 调用 <code>RegExp.prototype[Symbol.replace]</code></li>
        <li><code>String.prototype.search</code> 调用 <code>RegExp.prototype[Symbol.search]</code></li>
        <li><code>String.prototype.split</code> 调用 <code>RegExp.prototype[Symbol.split]</code></li>
    </ul>
    <h2><a href="#u-修饰符"  class="anchor" id="user-content-u-修饰符">

    </a>u 修饰符
    </h2>
    <p>ES6 对正则表达式添加了<code>u</code>修饰符，含义为“Unicode 模式”，用来正确处理大于<code>\uFFFF</code>的 Unicode 字符。也就是说，会正确处理四个字节的 UTF-16 编码。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-sr"><span class="pl-pds">/</span><span class="pl-k">^</span><span
            class="pl-c1">\uD83D</span><span class="pl-pds">/</span>u</span>.<span class="pl-c1">test</span>(<span
            class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\uD83D\uDC2A</span><span
            class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> false</span>
<span class="pl-sr"><span class="pl-pds">/</span><span class="pl-k">^</span><span class="pl-c1">\uD83D</span><span
        class="pl-pds">/</span></span>.<span class="pl-c1">test</span>(<span class="pl-s"><span
                class="pl-pds">'</span><span class="pl-cce">\uD83D\uDC2A</span><span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> true</span></pre>
    </div>
    <p>上面代码中，<code>\uD83D\uDC2A</code>是一个四个字节的 UTF-16 编码，代表一个字符。但是，ES5 不支持四个字节的 UTF-16 编码，会将其识别为两个字符，导致第二行代码结果为<code>true</code>。加了<code>u</code>修饰符以后，ES6
        就会识别其为一个字符，所以第一行代码结果为<code>false</code>。</p>
    <p>一旦加上<code>u</code>修饰符号，就会修改下面这些正则表达式的行为。</p>
    <p><strong>（1）点字符</strong></p>
    <p>点（<code>.</code>）字符在正则表达式中，含义是除了换行符以外的任意单个字符。对于码点大于<code>0xFFFF</code>的 Unicode 字符，点字符不能识别，必须加上<code>u</code>修饰符。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> s <span class="pl-k">=</span> <span
            class="pl-s"><span class="pl-pds">'</span>𠮷<span class="pl-pds">'</span></span>;

<span class="pl-sr"><span class="pl-pds">/</span><span class="pl-k">^</span><span class="pl-c1">.</span><span
        class="pl-k">$</span><span class="pl-pds">/</span></span>.<span class="pl-c1">test</span>(s) <span class="pl-c"><span
                class="pl-c">//</span> false</span>
<span class="pl-sr"><span class="pl-pds">/</span><span class="pl-k">^</span><span class="pl-c1">.</span><span
        class="pl-k">$</span><span class="pl-pds">/</span>u</span>.<span class="pl-c1">test</span>(s) <span
                class="pl-c"><span class="pl-c">//</span> true</span></pre>
    </div>
    <p>上面代码表示，如果不添加<code>u</code>修饰符，正则表达式就会认为字符串为两个字符，从而匹配失败。</p>
    <p><strong>（2）Unicode 字符表示法</strong></p>
    <p>ES6 新增了使用大括号表示 Unicode 字符，这种表示法在正则表达式中必须加上<code>u</code>修饰符，才能识别当中的大括号，否则会被解读为量词。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-sr"><span class="pl-pds">/</span><span
            class="pl-cce">\u</span><span class="pl-k">{61}</span><span class="pl-pds">/</span></span>.<span
            class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>a<span
            class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> false</span>
<span class="pl-sr"><span class="pl-pds">/</span><span class="pl-cce">\u</span><span class="pl-k">{61}</span><span
        class="pl-pds">/</span>u</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>a<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> true</span>
<span class="pl-sr"><span class="pl-pds">/</span><span class="pl-cce">\u</span>{20BB7}<span
        class="pl-pds">/</span>u</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>𠮷<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> true</span></pre>
    </div>
    <p>上面代码表示，如果不加<code>u</code>修饰符，正则表达式无法识别<code>\u{61}</code>这种表示法，只会认为这匹配 61 个连续的<code>u</code>。</p>
    <p><strong>（3）量词</strong></p>
    <p>使用<code>u</code>修饰符后，所有量词都会正确识别码点大于<code>0xFFFF</code>的 Unicode 字符。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-sr"><span class="pl-pds">/</span>a<span
            class="pl-k">{2}</span><span class="pl-pds">/</span></span>.<span class="pl-c1">test</span>(<span
            class="pl-s"><span class="pl-pds">'</span>aa<span class="pl-pds">'</span></span>) <span class="pl-c"><span
            class="pl-c">//</span> true</span>
<span class="pl-sr"><span class="pl-pds">/</span>a<span class="pl-k">{2}</span><span
        class="pl-pds">/</span>u</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>aa<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> true</span>
<span class="pl-sr"><span class="pl-pds">/</span>𠮷<span class="pl-k">{2}</span><span
        class="pl-pds">/</span></span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>𠮷𠮷<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> false</span>
<span class="pl-sr"><span class="pl-pds">/</span>𠮷<span class="pl-k">{2}</span><span
        class="pl-pds">/</span>u</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>𠮷𠮷<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> true</span></pre>
    </div>
    <p><strong>（4）预定义模式</strong></p>
    <p><code>u</code>修饰符也影响到预定义模式，能否正确识别码点大于<code>0xFFFF</code>的 Unicode 字符。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-sr"><span class="pl-pds">/</span><span class="pl-k">^</span><span
            class="pl-c1">\S</span><span class="pl-k">$</span><span class="pl-pds">/</span></span>.<span class="pl-c1">test</span>(<span
            class="pl-s"><span class="pl-pds">'</span>𠮷<span class="pl-pds">'</span></span>) <span class="pl-c"><span
            class="pl-c">//</span> false</span>
<span class="pl-sr"><span class="pl-pds">/</span><span class="pl-k">^</span><span class="pl-c1">\S</span><span
        class="pl-k">$</span><span class="pl-pds">/</span>u</span>.<span class="pl-c1">test</span>(<span
                class="pl-s"><span class="pl-pds">'</span>𠮷<span class="pl-pds">'</span></span>) <span
                class="pl-c"><span class="pl-c">//</span> true</span></pre>
    </div>
    <p>上面代码的<code>\S</code>是预定义模式，匹配所有不是空格的字符。只有加了<code>u</code>修饰符，它才能正确匹配码点大于<code>0xFFFF</code>的 Unicode 字符。</p>
    <p>利用这一点，可以写出一个正确返回字符串长度的函数。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">function</span> <span class="pl-en">codePointLength</span>(<span
            class="pl-smi">text</span>) {
  <span class="pl-k">var</span> result <span class="pl-k">=</span> <span class="pl-smi">text</span>.<span class="pl-c1">match</span>(<span
                class="pl-sr"><span class="pl-pds">/</span><span class="pl-c1">[<span
                class="pl-c1">\s\S</span>]</span><span class="pl-pds">/</span>gu</span>);
  <span class="pl-k">return</span> result <span class="pl-k">?</span> <span class="pl-smi">result</span>.<span
                class="pl-c1">length</span> <span class="pl-k">:</span> <span class="pl-c1">0</span>;
}

<span class="pl-k">var</span> s <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">'</span>𠮷𠮷<span
                class="pl-pds">'</span></span>;

<span class="pl-smi">s</span>.<span class="pl-c1">length</span> <span class="pl-c"><span class="pl-c">//</span> 4</span>
<span class="pl-en">codePointLength</span>(s) <span class="pl-c"><span class="pl-c">//</span> 2</span></pre>
    </div>
    <p><strong>（5）i 修饰符</strong></p>
    <p>有些 Unicode 字符的编码不同，但是字型很相近，比如，<code>\u004B</code>与<code>\u212A</code>都是大写的<code>K</code>。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-sr"><span class="pl-pds">/</span><span
            class="pl-c1">[<span class="pl-c1">a-z</span>]</span><span class="pl-pds">/</span>i</span>.<span
            class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\u212A</span><span
            class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> false</span>
<span class="pl-sr"><span class="pl-pds">/</span><span class="pl-c1">[<span class="pl-c1">a-z</span>]</span><span
        class="pl-pds">/</span>iu</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span
                class="pl-pds">'</span><span class="pl-cce">\u212A</span><span class="pl-pds">'</span></span>) <span
                class="pl-c"><span class="pl-c">//</span> true</span></pre>
    </div>
    <p>上面代码中，不加<code>u</code>修饰符，就无法识别非规范的<code>K</code>字符。</p>
    <h2><a href="#y-修饰符"  class="anchor" id="user-content-y-修饰符">

    </a>y 修饰符
    </h2>
    <p>除了<code>u</code>修饰符，ES6 还为正则表达式添加了<code>y</code>修饰符，叫做“粘连”（sticky）修饰符。</p>
    <p>
        <code>y</code>修饰符的作用与<code>g</code>修饰符类似，也是全局匹配，后一次匹配都从上一次匹配成功的下一个位置开始。不同之处在于，<code>g</code>修饰符只要剩余位置中存在匹配就可，而<code>y</code>修饰符确保匹配必须从剩余的第一个位置开始，这也就是“粘连”的涵义。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> s <span class="pl-k">=</span> <span
            class="pl-s"><span class="pl-pds">'</span>aaa_aa_a<span class="pl-pds">'</span></span>;
<span class="pl-k">var</span> r1 <span class="pl-k">=</span><span class="pl-sr"> <span class="pl-pds">/</span>a<span
                class="pl-k">+</span><span class="pl-pds">/</span>g</span>;
<span class="pl-k">var</span> r2 <span class="pl-k">=</span><span class="pl-sr"> <span class="pl-pds">/</span>a<span
                class="pl-k">+</span><span class="pl-pds">/</span>y</span>;

<span class="pl-smi">r1</span>.<span class="pl-c1">exec</span>(s) <span class="pl-c"><span class="pl-c">//</span> ["aaa"]</span>
<span class="pl-smi">r2</span>.<span class="pl-c1">exec</span>(s) <span class="pl-c"><span class="pl-c">//</span> ["aaa"]</span>

<span class="pl-smi">r1</span>.<span class="pl-c1">exec</span>(s) <span class="pl-c"><span class="pl-c">//</span> ["aa"]</span>
<span class="pl-smi">r2</span>.<span class="pl-c1">exec</span>(s) <span class="pl-c"><span
                class="pl-c">//</span> null</span></pre>
    </div>
    <p>
        上面代码有两个正则表达式，一个使用<code>g</code>修饰符，另一个使用<code>y</code>修饰符。这两个正则表达式各执行了两次，第一次执行的时候，两者行为相同，剩余字符串都是<code>_aa_a</code>。由于<code>g</code>修饰没有位置要求，所以第二次执行会返回结果，而<code>y</code>修饰符要求匹配必须从头部开始，所以返回<code>null</code>。
    </p>
    <p>如果改一下正则表达式，保证每次都能头部匹配，<code>y</code>修饰符就会返回结果了。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> s <span class="pl-k">=</span> <span
            class="pl-s"><span class="pl-pds">'</span>aaa_aa_a<span class="pl-pds">'</span></span>;
<span class="pl-k">var</span> r <span class="pl-k">=</span><span class="pl-sr"> <span class="pl-pds">/</span>a<span
                class="pl-k">+</span>_<span class="pl-pds">/</span>y</span>;

<span class="pl-smi">r</span>.<span class="pl-c1">exec</span>(s) <span class="pl-c"><span class="pl-c">//</span> ["aaa_"]</span>
<span class="pl-smi">r</span>.<span class="pl-c1">exec</span>(s) <span class="pl-c"><span class="pl-c">//</span> ["aa_"]</span></pre>
    </div>
    <p>上面代码每次匹配，都是从剩余字符串的头部开始。</p>
    <p>使用<code>lastIndex</code>属性，可以更好地说明<code>y</code>修饰符。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span
            class="pl-c1">REGEX</span> <span class="pl-k">=</span><span class="pl-sr"> <span
            class="pl-pds">/</span>a<span class="pl-pds">/</span>g</span>;

<span class="pl-c"><span class="pl-c">//</span> 指定从2号位置（y）开始匹配</span>
<span class="pl-c1">REGEX</span>.<span class="pl-c1">lastIndex</span> <span class="pl-k">=</span> <span
                class="pl-c1">2</span>;

<span class="pl-c"><span class="pl-c">//</span> 匹配成功</span>
<span class="pl-k">const</span> <span class="pl-c1">match</span> <span class="pl-k">=</span> <span
                class="pl-c1">REGEX</span>.<span class="pl-c1">exec</span>(<span class="pl-s"><span
                class="pl-pds">'</span>xaya<span class="pl-pds">'</span></span>);

<span class="pl-c"><span class="pl-c">//</span> 在3号位置匹配成功</span>
<span class="pl-smi">match</span>.<span class="pl-c1">index</span> <span class="pl-c"><span
                class="pl-c">//</span> 3</span>

<span class="pl-c"><span class="pl-c">//</span> 下一次匹配从4号位开始</span>
<span class="pl-c1">REGEX</span>.<span class="pl-c1">lastIndex</span> <span class="pl-c"><span class="pl-c">//</span> 4</span>

<span class="pl-c"><span class="pl-c">//</span> 4号位开始匹配失败</span>
<span class="pl-c1">REGEX</span>.<span class="pl-c1">exec</span>(<span class="pl-s"><span
                class="pl-pds">'</span>xaxa<span class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> null</span></pre>
    </div>
    <p>上面代码中，<code>lastIndex</code>属性指定每次搜索的开始位置，<code>g</code>修饰符从这个位置开始向后搜索，直到发现匹配为止。</p>
    <p><code>y</code>修饰符同样遵守<code>lastIndex</code>属性，但是要求必须在<code>lastIndex</code>指定的位置发现匹配。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span
            class="pl-c1">REGEX</span> <span class="pl-k">=</span><span class="pl-sr"> <span
            class="pl-pds">/</span>a<span class="pl-pds">/</span>y</span>;

<span class="pl-c"><span class="pl-c">//</span> 指定从2号位置开始匹配</span>
<span class="pl-c1">REGEX</span>.<span class="pl-c1">lastIndex</span> <span class="pl-k">=</span> <span
                class="pl-c1">2</span>;

<span class="pl-c"><span class="pl-c">//</span> 不是粘连，匹配失败</span>
<span class="pl-c1">REGEX</span>.<span class="pl-c1">exec</span>(<span class="pl-s"><span
                class="pl-pds">'</span>xaya<span class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> null</span>

<span class="pl-c"><span class="pl-c">//</span> 指定从3号位置开始匹配</span>
<span class="pl-c1">REGEX</span>.<span class="pl-c1">lastIndex</span> <span class="pl-k">=</span> <span
                class="pl-c1">3</span>;

<span class="pl-c"><span class="pl-c">//</span> 3号位置是粘连，匹配成功</span>
<span class="pl-k">const</span> <span class="pl-c1">match</span> <span class="pl-k">=</span> <span
                class="pl-c1">REGEX</span>.<span class="pl-c1">exec</span>(<span class="pl-s"><span
                class="pl-pds">'</span>xaxa<span class="pl-pds">'</span></span>);
<span class="pl-smi">match</span>.<span class="pl-c1">index</span> <span class="pl-c"><span
                class="pl-c">//</span> 3</span>
<span class="pl-c1">REGEX</span>.<span class="pl-c1">lastIndex</span> <span class="pl-c"><span class="pl-c">//</span> 4</span></pre>
    </div>
    <p>实际上，<code>y</code>修饰符号隐含了头部匹配的标志<code>^</code>。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-sr"><span class="pl-pds">/</span>b<span
            class="pl-pds">/</span>y</span>.<span class="pl-c1">exec</span>(<span class="pl-s"><span
            class="pl-pds">'</span>aba<span class="pl-pds">'</span></span>)
<span class="pl-c"><span class="pl-c">//</span> null</span></pre>
    </div>
    <p>上面代码由于不能保证头部匹配，所以返回<code>null</code>。<code>y</code>修饰符的设计本意，就是让头部匹配的标志<code>^</code>在全局匹配中都有效。</p>
    <p>在<code>split</code>方法中使用<code>y</code>修饰符，原字符串必须以分隔符开头。这也意味着，只要匹配成功，数组的第一个成员肯定是空字符串。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> 没有找到匹配</span>
<span class="pl-s"><span class="pl-pds">'</span>x##<span class="pl-pds">'</span></span>.<span class="pl-c1">split</span>(<span
                class="pl-sr"><span class="pl-pds">/</span>#<span class="pl-pds">/</span>y</span>)
<span class="pl-c"><span class="pl-c">//</span> [ 'x##' ]</span>

<span class="pl-c"><span class="pl-c">//</span> 找到两个匹配</span>
<span class="pl-s"><span class="pl-pds">'</span>##x<span class="pl-pds">'</span></span>.<span class="pl-c1">split</span>(<span
                class="pl-sr"><span class="pl-pds">/</span>#<span class="pl-pds">/</span>y</span>)
<span class="pl-c"><span class="pl-c">//</span> [ '', '', 'x' ]</span></pre>
    </div>
    <p>后续的分隔符只有紧跟前面的分隔符，才会被识别。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-s"><span class="pl-pds">'</span>#x#<span
            class="pl-pds">'</span></span>.<span class="pl-c1">split</span>(<span class="pl-sr"><span
            class="pl-pds">/</span>#<span class="pl-pds">/</span>y</span>)
<span class="pl-c"><span class="pl-c">//</span> [ '', 'x#' ]</span>

<span class="pl-s"><span class="pl-pds">'</span>##<span class="pl-pds">'</span></span>.<span class="pl-c1">split</span>(<span
                class="pl-sr"><span class="pl-pds">/</span>#<span class="pl-pds">/</span>y</span>)
<span class="pl-c"><span class="pl-c">//</span> [ '', '', '' ]</span></pre>
    </div>
    <p>下面是字符串对象的<code>replace</code>方法的例子。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span
            class="pl-c1">REGEX</span> <span class="pl-k">=</span><span class="pl-sr"> <span
            class="pl-pds">/</span>a<span class="pl-pds">/</span>gy</span>;
<span class="pl-s"><span class="pl-pds">'</span>aaxa<span class="pl-pds">'</span></span>.<span
                class="pl-c1">replace</span>(<span class="pl-c1">REGEX</span>, <span class="pl-s"><span
                class="pl-pds">'</span>-<span class="pl-pds">'</span></span>) <span class="pl-c"><span
                class="pl-c">//</span> '--xa'</span></pre>
    </div>
    <p>上面代码中，最后一个<code>a</code>因为不是出现在下一次匹配的头部，所以不会被替换。</p>
    <p>单单一个<code>y</code>修饰符对<code>match</code>方法，只能返回第一个匹配，必须与<code>g</code>修饰符联用，才能返回所有匹配。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-s"><span class="pl-pds">'</span>a1a2a3<span
            class="pl-pds">'</span></span>.<span class="pl-c1">match</span>(<span class="pl-sr"><span
            class="pl-pds">/</span>a<span class="pl-c1">\d</span><span class="pl-pds">/</span>y</span>) <span
            class="pl-c"><span class="pl-c">//</span> ["a1"]</span>
<span class="pl-s"><span class="pl-pds">'</span>a1a2a3<span class="pl-pds">'</span></span>.<span
                class="pl-c1">match</span>(<span class="pl-sr"><span class="pl-pds">/</span>a<span
                class="pl-c1">\d</span><span class="pl-pds">/</span>gy</span>) <span class="pl-c"><span
                class="pl-c">//</span> ["a1", "a2", "a3"]</span></pre>
    </div>
    <p><code>y</code>修饰符的一个应用，是从字符串提取 token（词元），<code>y</code>修饰符确保了匹配之间不会有漏掉的字符。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span
            class="pl-c1">TOKEN_Y</span> <span class="pl-k">=</span><span class="pl-sr"> <span
            class="pl-pds">/</span><span class="pl-c1">\s</span><span class="pl-k">*</span>(<span
            class="pl-cce">\+</span><span class="pl-k">|</span><span class="pl-c1">[<span
            class="pl-c1">0-9</span>]</span><span class="pl-k">+</span>)<span class="pl-c1">\s</span><span class="pl-k">*</span><span
            class="pl-pds">/</span>y</span>;
<span class="pl-k">const</span> <span class="pl-c1">TOKEN_G</span>  <span class="pl-k">=</span><span
                class="pl-sr"> <span class="pl-pds">/</span><span class="pl-c1">\s</span><span
                class="pl-k">*</span>(<span class="pl-cce">\+</span><span class="pl-k">|</span><span
                class="pl-c1">[<span class="pl-c1">0-9</span>]</span><span class="pl-k">+</span>)<span
                class="pl-c1">\s</span><span class="pl-k">*</span><span class="pl-pds">/</span>g</span>;

<span class="pl-en">tokenize</span>(<span class="pl-c1">TOKEN_Y</span>, <span class="pl-s"><span class="pl-pds">'</span>3 + 4<span
                class="pl-pds">'</span></span>)
<span class="pl-c"><span class="pl-c">//</span> [ '3', '+', '4' ]</span>
<span class="pl-en">tokenize</span>(<span class="pl-c1">TOKEN_G</span>, <span class="pl-s"><span class="pl-pds">'</span>3 + 4<span
                class="pl-pds">'</span></span>)
<span class="pl-c"><span class="pl-c">//</span> [ '3', '+', '4' ]</span>

<span class="pl-k">function</span> <span class="pl-en">tokenize</span>(<span class="pl-c1">TOKEN_REGEX</span>, <span
                class="pl-smi">str</span>) {
  <span class="pl-k">let</span> result <span class="pl-k">=</span> [];
  <span class="pl-k">let</span> match;
  <span class="pl-k">while</span> (match <span class="pl-k">=</span> <span class="pl-c1">TOKEN_REGEX</span>.<span
                class="pl-c1">exec</span>(str)) {
    <span class="pl-smi">result</span>.<span class="pl-c1">push</span>(match[<span class="pl-c1">1</span>]);
  }
  <span class="pl-k">return</span> result;
}</pre>
    </div>
    <p>上面代码中，如果字符串里面没有非法字符，<code>y</code>修饰符与<code>g</code>修饰符的提取结果是一样的。但是，一旦出现非法字符，两者的行为就不一样了。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-en">tokenize</span>(<span
            class="pl-c1">TOKEN_Y</span>, <span class="pl-s"><span class="pl-pds">'</span>3x + 4<span
            class="pl-pds">'</span></span>)
<span class="pl-c"><span class="pl-c">//</span> [ '3' ]</span>
<span class="pl-en">tokenize</span>(<span class="pl-c1">TOKEN_G</span>, <span class="pl-s"><span class="pl-pds">'</span>3x + 4<span
                class="pl-pds">'</span></span>)
<span class="pl-c"><span class="pl-c">//</span> [ '3', '+', '4' ]</span></pre>
    </div>
    <p>上面代码中，<code>g</code>修饰符会忽略非法字符，而<code>y</code>修饰符不会，这样就很容易发现错误。</p>
    <h2><a href="#sticky-属性"  class="anchor" id="user-content-sticky-属性">

    </a>sticky 属性
    </h2>
    <p>与<code>y</code>修饰符相匹配，ES6 的正则对象多了<code>sticky</code>属性，表示是否设置了<code>y</code>修饰符。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> r <span class="pl-k">=</span><span
            class="pl-sr"> <span class="pl-pds">/</span>hello<span class="pl-c1">\d</span><span class="pl-pds">/</span>y</span>;
<span class="pl-smi">r</span>.<span class="pl-smi">sticky</span> <span class="pl-c"><span
                class="pl-c">//</span> true</span></pre>
    </div>
    <h2><a href="#flags-属性"  class="anchor" id="user-content-flags-属性">

    </a>flags 属性
    </h2>
    <p>ES6 为正则表达式新增了<code>flags</code>属性，会返回正则表达式的修饰符。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span
            class="pl-c">//</span> ES5 的 source 属性</span>
<span class="pl-c"><span class="pl-c">//</span> 返回正则表达式的正文</span>
<span class="pl-sr"><span class="pl-pds">/</span>abc<span class="pl-pds">/</span>ig</span>.<span
                class="pl-c1">source</span>
<span class="pl-c"><span class="pl-c">//</span> "abc"</span>

<span class="pl-c"><span class="pl-c">//</span> ES6 的 flags 属性</span>
<span class="pl-c"><span class="pl-c">//</span> 返回正则表达式的修饰符</span>
<span class="pl-sr"><span class="pl-pds">/</span>abc<span class="pl-pds">/</span>ig</span>.<span
                class="pl-smi">flags</span>
<span class="pl-c"><span class="pl-c">//</span> 'gi'</span></pre>
    </div>
    <h2><a href="#s-修饰符dotall-模式"  class="anchor" id="user-content-s-修饰符dotall-模式">

    </a>s 修饰符：dotAll 模式
    </h2>
    <p>正则表达式中，点（<code>.</code>）是一个特殊字符，代表任意的单个字符，但是行终止符（line terminator character）除外。</p>
    <p>以下四个字符属于”行终止符“。</p>
    <ul>
        <li>U+000A 换行符（<code>\n</code>）</li>
        <li>U+000D 回车符（<code>\r</code>）</li>
        <li>U+2028 行分隔符（line separator）</li>
        <li>U+2029 段分隔符（paragraph separator）</li>
    </ul>
    <div class="highlight highlight-source-js"><pre><span class="pl-sr"><span class="pl-pds">/</span>foo<span
            class="pl-c1">.</span>bar<span class="pl-pds">/</span></span>.<span class="pl-c1">test</span>(<span
            class="pl-s"><span class="pl-pds">'</span>foo<span class="pl-cce">\n</span>bar<span class="pl-pds">'</span></span>)
<span class="pl-c"><span class="pl-c">//</span> false</span></pre>
    </div>
    <p>上面代码中，因为<code>.</code>不匹配<code>\n</code>，所以正则表达式返回<code>false</code>。</p>
    <p>但是，很多时候我们希望匹配的是任意单个字符，这时有一种变通的写法。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-sr"><span class="pl-pds">/</span>foo<span
            class="pl-c1">[<span class="pl-k">^</span>]</span>bar<span class="pl-pds">/</span></span>.<span
            class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>foo<span class="pl-cce">\n</span>bar<span
            class="pl-pds">'</span></span>)
<span class="pl-c"><span class="pl-c">//</span> true</span></pre>
    </div>
    <p>这种解决方案毕竟不太符合直觉，所以现在有一个<a href="https://github.com/mathiasbynens/es-regexp-dotall-flag">提案</a>，引入<code>/s</code>修饰符，使得<code>.</code>可以匹配任意单个字符。
    </p>
    <div class="highlight highlight-source-js">
        <pre><span class="pl-sr"><span class="pl-pds">/</span>foo<span class="pl-c1">.</span>bar<span
                class="pl-pds">/</span></span><span class="pl-smi">s</span>.<span class="pl-c1">test</span>(<span
                class="pl-s"><span class="pl-pds">'</span>foo<span class="pl-cce">\n</span>bar<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> true</span></pre>
    </div>
    <p>
        这被称为<code>dotAll</code>模式，即点（dot）代表一切字符。所以，正则表达式还引入了一个<code>dotAll</code>属性，返回一个布尔值，表示该正则表达式是否处在<code>dotAll</code>模式。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">re</span> <span
            class="pl-k">=</span><span class="pl-sr"> <span class="pl-pds">/</span>foo<span
            class="pl-c1">.</span>bar<span class="pl-pds">/</span></span>s;
<span class="pl-c"><span class="pl-c">//</span> 另一种写法</span>
<span class="pl-c"><span class="pl-c">//</span> const re = new RegExp('foo.bar', 's');</span>

<span class="pl-smi">re</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>foo<span
                class="pl-cce">\n</span>bar<span class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> true</span>
<span class="pl-smi">re</span>.<span class="pl-smi">dotAll</span> <span class="pl-c"><span
                class="pl-c">//</span> true</span>
<span class="pl-smi">re</span>.<span class="pl-smi">flags</span> <span class="pl-c"><span
                class="pl-c">//</span> 's'</span></pre>
    </div>
    <p><code>/s</code>修饰符和多行修饰符<code>/m</code>不冲突，两者一起使用的情况下，<code>.</code>匹配所有字符，而<code>^</code>和<code>$</code>匹配每一行的行首和行尾。
    </p>
    <h2><a href="#后行断言"  class="anchor" id="user-content-后行断言">

    </a>后行断言
    </h2>
    <p>JavaScript 语言的正则表达式，只支持先行断言（lookahead）和先行否定断言（negative lookahead），不支持后行断言（lookbehind）和后行否定断言（negative
        lookbehind）。目前，有一个<a href="https://github.com/goyakin/es-regexp-lookbehind">提案</a>，引入后行断言，V8 引擎 4.9 版已经支持。</p>
    <p>
        ”先行断言“指的是，<code>x</code>只有在<code>y</code>前面才匹配，必须写成<code>/x(?=y)/</code>。比如，只匹配百分号之前的数字，要写成<code>/\d+(?=%)/</code>。”先行否定断言“指的是，<code>x</code>只有不在<code>y</code>前面才匹配，必须写成<code>/x(?!y)/</code>。比如，只匹配不在百分号之前的数字，要写成<code>/\d+(?!%)/</code>。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-sr"><span class="pl-pds">/</span><span
            class="pl-c1">\d</span><span class="pl-k">+</span>(?=%)<span class="pl-pds">/</span></span>.<span
            class="pl-c1">exec</span>(<span class="pl-s"><span class="pl-pds">'</span>100% of US presidents have been male<span
            class="pl-pds">'</span></span>)  <span class="pl-c"><span class="pl-c">//</span> ["100"]</span>
<span class="pl-sr"><span class="pl-pds">/</span><span class="pl-c1">\d</span><span class="pl-k">+</span>(?!%)<span
        class="pl-pds">/</span></span>.<span class="pl-c1">exec</span>(<span class="pl-s"><span class="pl-pds">'</span>that’s all 44 of them<span
                class="pl-pds">'</span></span>)                 <span class="pl-c"><span
                class="pl-c">//</span> ["44"]</span></pre>
    </div>
    <p>上面两个字符串，如果互换正则表达式，就不会得到相同结果。另外，还可以看到，”先行断言“括号之中的部分（<code>(?=%)</code>），是不计入返回结果的。</p>
    <p>“后行断言”正好与“先行断言”相反，<code>x</code>只有在<code>y</code>后面才匹配，必须写成<code>/(?&lt;=y)x/</code>。比如，只匹配美元符号之后的数字，要写成<code>/(?&lt;=\$)\d+/</code>。”后行否定断言“则与”先行否定断言“相反，<code>x</code>只有不在<code>y</code>后面才匹配，必须写成<code>/(?&lt;!y)x/</code>。比如，只匹配不在美元符号后面的数字，要写成<code>/(?&lt;!\$)\d+/</code>。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-sr"><span class="pl-pds">/</span>(<span
            class="pl-k">?</span>&lt;=<span class="pl-cce">\$</span>)<span class="pl-c1">\d</span><span
            class="pl-k">+</span><span class="pl-pds">/</span></span>.<span class="pl-c1">exec</span>(<span
            class="pl-s"><span class="pl-pds">'</span>Benjamin Franklin is on the $100 bill<span class="pl-pds">'</span></span>)  <span
            class="pl-c"><span class="pl-c">//</span> ["100"]</span>
<span class="pl-sr"><span class="pl-pds">/</span>(<span class="pl-k">?</span>&lt;!<span class="pl-cce">\$</span>)<span
        class="pl-c1">\d</span><span class="pl-k">+</span><span class="pl-pds">/</span></span>.<span
                class="pl-c1">exec</span>(<span class="pl-s"><span class="pl-pds">'</span>it’s is worth about €90<span
                class="pl-pds">'</span></span>)                <span class="pl-c"><span
                class="pl-c">//</span> ["90"]</span></pre>
    </div>
    <p>上面的例子中，“后行断言”的括号之中的部分（<code>(?&lt;=\$)</code>），也是不计入返回结果。</p>
    <p>下面的例子是使用后行断言进行字符串替换。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span
            class="pl-c1">RE_DOLLAR_PREFIX</span> <span class="pl-k">=</span><span class="pl-sr"> <span
            class="pl-pds">/</span>(<span class="pl-k">?</span>&lt;=<span class="pl-cce">\$</span>)foo<span
            class="pl-pds">/</span>g</span>;
<span class="pl-s"><span class="pl-pds">'</span>$foo %foo foo<span class="pl-pds">'</span></span>.<span class="pl-c1">replace</span>(<span
                class="pl-c1">RE_DOLLAR_PREFIX</span>, <span class="pl-s"><span class="pl-pds">'</span>bar<span
                class="pl-pds">'</span></span>);
<span class="pl-c"><span class="pl-c">//</span> '$bar %foo foo'</span></pre>
    </div>
    <p>上面代码中，只有在美元符号后面的<code>foo</code>才会被替换。</p>
    <p>“后行断言”的实现，需要先匹配<code>/(?&lt;=y)x/</code>的<code>x</code>，然后再回到左边，匹配<code>y</code>的部分。这种“先右后左”的执行顺序，与所有其他正则操作相反，导致了一些不符合预期的行为。
    </p>
    <p>首先，”后行断言“的组匹配，与正常情况下结果是不一样的。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-sr"><span class="pl-pds">/</span>(<span
            class="pl-k">?</span>&lt;=(<span class="pl-c1">\d</span><span class="pl-k">+</span>)(<span
            class="pl-c1">\d</span><span class="pl-k">+</span>))<span class="pl-k">$</span><span class="pl-pds">/</span></span>.<span
            class="pl-c1">exec</span>(<span class="pl-s"><span class="pl-pds">'</span>1053<span class="pl-pds">'</span></span>) <span
            class="pl-c"><span class="pl-c">//</span> ["", "1", "053"]</span>
<span class="pl-sr"><span class="pl-pds">/</span><span class="pl-k">^</span>(<span class="pl-c1">\d</span><span
        class="pl-k">+</span>)(<span class="pl-c1">\d</span><span class="pl-k">+</span>)<span class="pl-k">$</span><span
        class="pl-pds">/</span></span>.<span class="pl-c1">exec</span>(<span class="pl-s"><span class="pl-pds">'</span>1053<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span
                class="pl-c">//</span> ["1053", "105", "3"]</span></pre>
    </div>
    <p>上面代码中，需要捕捉两个组匹配。没有"后行断言"时，第一个括号是贪婪模式，第二个括号只能捕获一个字符，所以结果是<code>105</code>和<code>3</code>。而"后行断言"时，由于执行顺序是从右到左，第二个括号是贪婪模式，第一个括号只能捕获一个字符，所以结果是<code>1</code>和<code>053</code>。
    </p>
    <p>其次，"后行断言"的反斜杠引用，也与通常的顺序相反，必须放在对应的那个括号之前。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-sr"><span class="pl-pds">/</span>(<span
            class="pl-k">?</span>&lt;=(o)d<span class="pl-k">\1</span>)r<span class="pl-pds">/</span></span>.<span
            class="pl-c1">exec</span>(<span class="pl-s"><span class="pl-pds">'</span>hodor<span class="pl-pds">'</span></span>)  <span
            class="pl-c"><span class="pl-c">//</span> null</span>
<span class="pl-sr"><span class="pl-pds">/</span>(<span class="pl-k">?</span>&lt;=<span
        class="pl-k">\1</span>d(o))r<span class="pl-pds">/</span></span>.<span class="pl-c1">exec</span>(<span
                class="pl-s"><span class="pl-pds">'</span>hodor<span class="pl-pds">'</span></span>)  <span
                class="pl-c"><span class="pl-c">//</span> ["r", "o"]</span></pre>
    </div>
    <p>上面代码中，如果后行断言的反斜杠引用（<code>\1</code>）放在括号的后面，就不会得到匹配结果，必须放在前面才可以。因为后行断言是先从左到右扫描，发现匹配以后再回过头，从右到左完成反斜杠引用。</p>
    <h2><a href="#unicode-属性类"  class="anchor" id="user-content-unicode-属性类">

    </a>Unicode 属性类
    </h2>
    <p>目前，有一个<a href="https://github.com/mathiasbynens/es-regexp-unicode-property-escapes">提案</a>，引入了一种新的类的写法<code>\p{...}</code>和<code>\P{...}</code>，允许正则表达式匹配符合
        Unicode 某种属性的所有字符。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span
            class="pl-c1">regexGreekSymbol</span> <span class="pl-k">=</span><span class="pl-sr"> <span
            class="pl-pds">/</span><span class="pl-cce">\p</span>{Script=Greek}<span class="pl-pds">/</span>u</span>;
<span class="pl-smi">regexGreekSymbol</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span
                class="pl-pds">'</span>π<span class="pl-pds">'</span></span>) <span class="pl-c"><span
                class="pl-c">//</span> true</span></pre>
    </div>
    <p>上面代码中，<code>\p{Script=Greek}</code>指定匹配一个希腊文字母，所以匹配<code>π</code>成功。</p>
    <p>Unicode 属性类要指定属性名和属性值。</p>
    <div class="highlight highlight-source-js">
        <pre>\p{UnicodePropertyName<span class="pl-k">=</span>UnicodePropertyValue}</pre>
    </div>
    <p>对于某些属性，可以只写属性名。</p>
    <div class="highlight highlight-source-js">
        <pre>\p{UnicodePropertyName}</pre>
    </div>
    <p><code>\P{…}</code>是<code>\p{…}</code>的反向匹配，即匹配不满足条件的字符。</p>
    <p>注意，这两种类只对 Unicode 有效，所以使用的时候一定要加上<code>u</code>修饰符。如果不加<code>u</code>修饰符，正则表达式使用<code>\p</code>和<code>\P</code>会报错，ECMAScript
        预留了这两个类。</p>
    <p>由于 Unicode 的各种属性非常多，所以这种新的类的表达能力非常强。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span
            class="pl-c1">regex</span> <span class="pl-k">=</span><span class="pl-sr"> <span
            class="pl-pds">/</span><span class="pl-k">^</span><span class="pl-cce">\p</span>{Decimal_Number}<span
            class="pl-k">+</span><span class="pl-k">$</span><span class="pl-pds">/</span>u</span>;
<span class="pl-smi">regex</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>𝟏𝟐𝟑𝟜𝟝𝟞𝟩𝟪𝟫𝟬𝟭𝟮𝟯𝟺𝟻𝟼<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> true</span></pre>
    </div>
    <p>上面代码中，属性类指定匹配所有十进制字符，可以看到各种字型的十进制字符都会匹配成功。</p>
    <p><code>\p{Number}</code>甚至能匹配罗马数字。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> 匹配所有数字</span>
<span class="pl-k">const</span> <span class="pl-c1">regex</span> <span class="pl-k">=</span><span class="pl-sr"> <span
                class="pl-pds">/</span><span class="pl-k">^</span><span class="pl-cce">\p</span>{Number}<span
                class="pl-k">+</span><span class="pl-k">$</span><span class="pl-pds">/</span>u</span>;
<span class="pl-smi">regex</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>²³¹¼½¾<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> true</span>
<span class="pl-smi">regex</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span
                class="pl-pds">'</span>㉛㉜㉝<span class="pl-pds">'</span></span>) <span class="pl-c"><span
                class="pl-c">//</span> true</span>
<span class="pl-smi">regex</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> true</span></pre>
    </div>
    <p>下面是其他一些例子。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> 匹配各种文字的所有字母，等同于 Unicode 版的 \w</span>
[\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]

<span class="pl-c"><span class="pl-c">//</span> 匹配各种文字的所有非字母的字符，等同于 Unicode 版的 \W</span>
[<span class="pl-k">^</span>\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]

<span class="pl-c"><span class="pl-c">//</span> 匹配所有的箭头字符</span>
<span class="pl-k">const</span> <span class="pl-c1">regexArrows</span> <span class="pl-k">=</span><span
                class="pl-sr"> <span class="pl-pds">/</span><span class="pl-k">^</span><span class="pl-cce">\p</span>{Block=Arrows}<span
                class="pl-k">+</span><span class="pl-k">$</span><span class="pl-pds">/</span>u</span>;
<span class="pl-smi">regexArrows</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>←↑→↓↔↕↖↗↘↙⇏⇐⇑⇒⇓⇔⇕⇖⇗⇘⇙⇧⇩<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> true</span></pre>
    </div>
    <h2><a href="#具名组匹配"  class="anchor" id="user-content-具名组匹配">

    </a>具名组匹配
    </h2>
    <h3><a href="#简介"  class="anchor" id="user-content-简介">

    </a>简介
    </h3>
    <p>正则表达式使用圆括号进行组匹配。</p>
    <div class="highlight highlight-source-js">
        <pre><span class="pl-k">const</span> <span class="pl-c1">RE_DATE</span> <span class="pl-k">=</span><span
                class="pl-sr"> <span class="pl-pds">/</span>(<span class="pl-c1">\d</span><span class="pl-k">{4}</span>)-(<span
                class="pl-c1">\d</span><span class="pl-k">{2}</span>)-(<span class="pl-c1">\d</span><span class="pl-k">{2}</span>)<span
                class="pl-pds">/</span></span>;</pre>
    </div>
    <p>上面代码中，正则表达式里面有三组圆括号。使用<code>exec</code>方法，就可以将这三组匹配结果提取出来。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">matchObj</span> <span
            class="pl-k">=</span> <span class="pl-c1">RE_DATE</span>.<span class="pl-c1">exec</span>(<span class="pl-s"><span
            class="pl-pds">'</span>1999-12-31<span class="pl-pds">'</span></span>);
<span class="pl-k">const</span> <span class="pl-c1">year</span> <span class="pl-k">=</span> matchObj[<span
                class="pl-c1">1</span>]; <span class="pl-c"><span class="pl-c">//</span> 1999</span>
<span class="pl-k">const</span> <span class="pl-c1">month</span> <span class="pl-k">=</span> matchObj[<span
                class="pl-c1">2</span>]; <span class="pl-c"><span class="pl-c">//</span> 12</span>
<span class="pl-k">const</span> <span class="pl-c1">day</span> <span class="pl-k">=</span> matchObj[<span class="pl-c1">3</span>]; <span
                class="pl-c"><span class="pl-c">//</span> 31</span></pre>
    </div>
    <p>组匹配的一个问题是，每一组的匹配含义不容易看出来，而且只能用数字序号引用，要是组的顺序变了，引用的时候就必须修改序号。</p>
    <p>现在有一个“具名组匹配”（Named Capture Groups）的<a href="https://github.com/tc39/proposal-regexp-named-groups">提案</a>，允许为每一个组匹配指定一个名字，既便于阅读代码，又便于引用。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span
            class="pl-c1">RE_DATE</span> <span class="pl-k">=</span><span class="pl-sr"> <span
            class="pl-pds">/</span>(<span class="pl-k">?</span>&lt;year&gt;<span class="pl-c1">\d</span><span
            class="pl-k">{4}</span>)-(<span class="pl-k">?</span>&lt;month&gt;<span class="pl-c1">\d</span><span
            class="pl-k">{2}</span>)-(<span class="pl-k">?</span>&lt;day&gt;<span class="pl-c1">\d</span><span
            class="pl-k">{2}</span>)<span class="pl-pds">/</span></span>;

<span class="pl-k">const</span> <span class="pl-c1">matchObj</span> <span class="pl-k">=</span> <span class="pl-c1">RE_DATE</span>.<span
                class="pl-c1">exec</span>(<span class="pl-s"><span class="pl-pds">'</span>1999-12-31<span
                class="pl-pds">'</span></span>);
<span class="pl-k">const</span> <span class="pl-c1">year</span> <span class="pl-k">=</span> <span class="pl-smi">matchObj</span>.<span
                class="pl-smi">groups</span>.<span class="pl-smi">year</span>; <span class="pl-c"><span
                class="pl-c">//</span> 1999</span>
<span class="pl-k">const</span> <span class="pl-c1">month</span> <span class="pl-k">=</span> <span class="pl-smi">matchObj</span>.<span
                class="pl-smi">groups</span>.<span class="pl-smi">month</span>; <span class="pl-c"><span
                class="pl-c">//</span> 12</span>
<span class="pl-k">const</span> <span class="pl-c1">day</span> <span class="pl-k">=</span> <span
                class="pl-smi">matchObj</span>.<span class="pl-smi">groups</span>.<span class="pl-smi">day</span>; <span
                class="pl-c"><span class="pl-c">//</span> 31</span></pre>
    </div>
    <p>上面代码中，“具名组匹配”在圆括号内部，模式的头部添加“问号 + 尖括号 +
        组名”（<code>?&lt;year&gt;</code>），然后就可以在<code>exec</code>方法返回结果的<code>groups</code>属性上引用该组名。同时，数字序号（<code>matchObj[1]</code>）依然有效。
    </p>
    <p>具名组匹配等于为每一组匹配加上了 ID，便于描述匹配的目的。如果组的顺序变了，也不用改变匹配后的处理代码。</p>
    <p>如果具名组没有匹配，那么对应的<code>groups</code>对象属性会是<code>undefined</code>。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">RE_OPT_A</span> <span
            class="pl-k">=</span><span class="pl-sr"> <span class="pl-pds">/</span><span class="pl-k">^</span>(<span
            class="pl-k">?</span>&lt;as&gt;a<span class="pl-k">+</span>)<span class="pl-k">?</span><span
            class="pl-k">$</span><span class="pl-pds">/</span></span>;
<span class="pl-k">const</span> <span class="pl-c1">matchObj</span> <span class="pl-k">=</span> <span class="pl-c1">RE_OPT_A</span>.<span
                class="pl-c1">exec</span>(<span class="pl-s"><span class="pl-pds">'</span><span class="pl-pds">'</span></span>);

<span class="pl-smi">matchObj</span>.<span class="pl-smi">groups</span>.<span class="pl-smi">as</span> <span
                class="pl-c"><span class="pl-c">//</span> undefined</span>
<span class="pl-s"><span class="pl-pds">'</span>as<span class="pl-pds">'</span></span> <span
                class="pl-k">in</span> <span class="pl-smi">matchObj</span>.<span class="pl-smi">groups</span> <span
                class="pl-c"><span class="pl-c">//</span> true</span></pre>
    </div>
    <p>上面代码中，具名组<code>as</code>没有找到匹配，那么<code>matchObj.groups.as</code>属性值就是<code>undefined</code>，并且<code>as</code>这个键名在<code>groups</code>是始终存在的。
    </p>
    <h3><a href="#解构赋值和替换"  class="anchor" id="user-content-解构赋值和替换">

    </a>解构赋值和替换
    </h3>
    <p>有了具名组匹配以后，可以使用解构赋值直接从匹配结果上为变量赋值。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">let</span> {groups<span class="pl-k">:</span> {one, two}} <span
            class="pl-k">=</span><span class="pl-sr"> <span class="pl-pds">/</span><span class="pl-k">^</span>(<span
            class="pl-k">?</span>&lt;one&gt;<span class="pl-c1">.</span><span class="pl-k">*</span>):(<span
            class="pl-k">?</span>&lt;two&gt;<span class="pl-c1">.</span><span class="pl-k">*</span>)<span
            class="pl-k">$</span><span class="pl-pds">/</span>u</span>.<span class="pl-c1">exec</span>(<span
            class="pl-s"><span class="pl-pds">'</span>foo:bar<span class="pl-pds">'</span></span>);
one  <span class="pl-c"><span class="pl-c">//</span> foo</span>
two  <span class="pl-c"><span class="pl-c">//</span> bar</span></pre>
    </div>
    <p>字符串替换时，使用<code>$&lt;组名&gt;</code>引用具名组。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">let</span> re <span class="pl-k">=</span><span
            class="pl-sr"> <span class="pl-pds">/</span>(<span class="pl-k">?</span>&lt;year&gt;<span
            class="pl-c1">\d</span><span class="pl-k">{4}</span>)-(<span class="pl-k">?</span>&lt;month&gt;<span
            class="pl-c1">\d</span><span class="pl-k">{2}</span>)-(<span class="pl-k">?</span>&lt;day&gt;<span
            class="pl-c1">\d</span><span class="pl-k">{2}</span>)<span class="pl-pds">/</span>u</span>;

<span class="pl-s"><span class="pl-pds">'</span>2015-01-02<span class="pl-pds">'</span></span>.<span class="pl-c1">replace</span>(re, <span
                class="pl-s"><span class="pl-pds">'</span>$&lt;day&gt;/$&lt;month&gt;/$&lt;year&gt;<span class="pl-pds">'</span></span>)
<span class="pl-c"><span class="pl-c">//</span> '02/01/2015'</span></pre>
    </div>
    <p>上面代码中，<code>replace</code>方法的第二个参数是一个字符串，而不是正则表达式。</p>
    <p><code>replace</code>方法的第二个参数也可以是函数，该函数的参数序列如下。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-s"><span class="pl-pds">'</span>2015-01-02<span
            class="pl-pds">'</span></span>.<span class="pl-c1">replace</span>(re, (
   matched, <span class="pl-c"><span class="pl-c">//</span> 整个匹配结果 2015-01-02</span>
   capture1, <span class="pl-c"><span class="pl-c">//</span> 第一个组匹配 2015</span>
   capture2, <span class="pl-c"><span class="pl-c">//</span> 第二个组匹配 01</span>
   capture3, <span class="pl-c"><span class="pl-c">//</span> 第三个组匹配 02</span>
   position, <span class="pl-c"><span class="pl-c">//</span> 匹配开始的位置 0</span>
   <span class="pl-c1">S</span>, <span class="pl-c"><span class="pl-c">//</span> 原字符串 2015-01-02</span>
   groups <span class="pl-c"><span class="pl-c">//</span> 具名组构成的一个对象 {year, month, day}</span>
 ) <span class="pl-k">=&gt;</span> {
 <span class="pl-k">let</span> {day, month, year} <span class="pl-k">=</span> args[<span
                class="pl-smi">args</span>.<span class="pl-c1">length</span> <span class="pl-k">-</span> <span
                class="pl-c1">1</span>];
 <span class="pl-k">return</span> <span class="pl-s"><span class="pl-pds">`</span><span class="pl-s1"><span
                class="pl-pse">${</span>day<span class="pl-pse">}</span></span>/<span class="pl-s1"><span
                class="pl-pse">${</span>month<span class="pl-pse">}</span></span>/<span class="pl-s1"><span
                class="pl-pse">${</span>year<span class="pl-pse">}</span></span><span class="pl-pds">`</span></span>;
});</pre>
    </div>
    <p>具名组匹配在原来的基础上，新增了最后一个函数参数：具名组构成的一个对象。函数内部可以直接对这个对象进行解构赋值。</p>
    <h3><a href="#引用"  class="anchor" id="user-content-引用">

    </a>引用
    </h3>
    <p>如果要在正则表达式内部引用某个“具名组匹配”，可以使用<code>\k&lt;组名&gt;</code>的写法。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">RE_TWICE</span> <span
            class="pl-k">=</span><span class="pl-sr"> <span class="pl-pds">/</span><span class="pl-k">^</span>(<span
            class="pl-k">?</span>&lt;word&gt;<span class="pl-c1">[<span class="pl-c1">a-z</span>]</span><span
            class="pl-k">+</span>)!<span class="pl-cce">\k</span>&lt;word&gt;<span class="pl-k">$</span><span
            class="pl-pds">/</span></span>;
<span class="pl-c1">RE_TWICE</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>abc!abc<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> true</span>
<span class="pl-c1">RE_TWICE</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>abc!ab<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> false</span></pre>
    </div>
    <p>数字引用（<code>\1</code>）依然有效。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">RE_TWICE</span> <span
            class="pl-k">=</span><span class="pl-sr"> <span class="pl-pds">/</span><span class="pl-k">^</span>(<span
            class="pl-k">?</span>&lt;word&gt;<span class="pl-c1">[<span class="pl-c1">a-z</span>]</span><span
            class="pl-k">+</span>)!<span class="pl-k">\1</span><span class="pl-k">$</span><span class="pl-pds">/</span></span>;
<span class="pl-c1">RE_TWICE</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>abc!abc<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> true</span>
<span class="pl-c1">RE_TWICE</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>abc!ab<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> false</span></pre>
    </div>
    <p>这两种引用语法还可以同时使用。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">RE_TWICE</span> <span
            class="pl-k">=</span><span class="pl-sr"> <span class="pl-pds">/</span><span class="pl-k">^</span>(<span
            class="pl-k">?</span>&lt;word&gt;<span class="pl-c1">[<span class="pl-c1">a-z</span>]</span><span
            class="pl-k">+</span>)!<span class="pl-cce">\k</span>&lt;word&gt;!<span class="pl-k">\1</span><span
            class="pl-k">$</span><span class="pl-pds">/</span></span>;
<span class="pl-c1">RE_TWICE</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>abc!abc!abc<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> true</span>
<span class="pl-c1">RE_TWICE</span>.<span class="pl-c1">test</span>(<span class="pl-s"><span class="pl-pds">'</span>abc!abc!ab<span
                class="pl-pds">'</span></span>) <span class="pl-c"><span class="pl-c">//</span> false</span></pre>
    </div>
</div>
</body>
</html>
